#ifndef BASE_FAST_STRING_H
#define BASE_FAST_STRING_H
/*
 * Copyright (C) 2011 Alexey Solomin, a.rainman on gmail point com
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */

#include <string>
#include <cstdint>
// Workaround - TODO
#ifndef SIZE_MAX
#define SIZE_MAX __SIZE_T_MAX__
#endif

//#include <algorithm>
#include <stdio.h>
#include <stdint.h>
#include "Util.h"
//==============================================================================
// To prevent the overseas operations offset by a faststring (eg when calling the function substr) enable this option
// #define _SAVE_FASTSTRING
//==============================================================================
template <typename base_type, typename base_ptr>
class base_fast_string
{
  protected:
    base_ptr m_startPointer;
    base_ptr m_endPointer;
    size_t m_size;
    size_t m_capacity;
    void updateSize()
    {
      m_size = m_endPointer - m_startPointer;
    }
    bool isValidPointer(const base_ptr& p_pointer) const
    {
      return p_pointer >= begin() && p_pointer <= end();
    }
  public:
    const static size_t npos = SIZE_MAX;
    base_fast_string()
    {
      m_startPointer = NULL;
      m_endPointer = NULL;
      m_size = 0;
      m_capacity = 0;
    }
    base_fast_string(const base_ptr& p_startPointer, size_t p_size) : m_startPointer(p_startPointer), m_endPointer(p_startPointer + p_size), m_size(p_size), m_capacity(p_size) { }
    base_fast_string(const base_ptr& p_startPointer) : m_startPointer(p_startPointer), m_size(strlen(p_startPointer))
    {
      m_endPointer = m_startPointer + size();
      m_capacity = size();
    }
    base_fast_string(const base_ptr& p_startPointer, const base_ptr& p_endPointer) : m_startPointer(p_startPointer), m_endPointer(p_endPointer)
    {
      updateSize();
      m_capacity = size();
    }
    int compare(const base_fast_string& str) const
    {
      const int retVal = size() - str.size();
      if (retVal == 0)
        return memcmp(begin(), str.begin(), size());
        
      return retVal;
    }
    int compare(size_t pos1, size_t count1, const base_fast_string& str) const
    {
      const int retVal = pos1 + count1 - str.size();
      if (retVal == 0)
        return comparedata(begin() + pos1, count1, str);
        
      return retVal;
    }
    int compare(size_t pos1, size_t count1, const base_ptr s) const
    {
      const int retVal = pos1 + count1 - strlen(s);
      if (retVal == 0)
        return memcmp(begin() + pos1, s, count1);
        
      return retVal;
    }
    size_t indexof(const Pointer& p_pointer) const
    {
      return isValidPointer(p_pointer) ? p_pointer - begin() : npos;
    }
    /* TODO
    Complite ?int compare( const basic_string& str ) const;?
    (1)
    ?int compare( size_type pos1, size_type count1,
                 const basic_string& str ) const;?
    (2)
    ?int compare( size_type pos1, size_type count1,
                 const basic_string& str,
                 size_type pos2, size_type count2 ) const;?
    (3)
    ?int compare( const CharT* s ) const noexcept;?
    (4)
    ?int compare( size_type pos1, size_type count1,
                 const CharT* s ) const;?
    (5)
    ?int compare( size_type pos1, size_type count1,
                 const CharT* s, size_type count2 ) const;?
    (6)
    */
    bool operator ==(const base_fast_string& str) const
    {
      return compare(str) == 0;
    }
    bool operator !=(const base_fast_string& str) const
    {
      return compare(str) != 0;
    }
    bool operator >(const base_fast_string& str) const
    {
      return compare(str) > 0;
    }
    bool operator <(const base_fast_string& str) const
    {
      return compare(str) < 0;
    }
    size_t size() const
    {
      return m_size;
    }
    size_t length() const
    {
      return size();
    }
    size_t capacity() const
    {
      return m_capacity;
    }
    void resize(size_t count)
    {
#ifdef _SAVE_FASTSTRING
      if (count > capacity())
        count = capacity();
#endif // _SAVE_FASTSTRING
        
      m_endPointer = begin() + count;
      updateSize();
    }
    bool empty() const
    {
      return m_size == 0;
    }
    base_ptr begin() const
    {
      return m_startPointer;
    }
    base_ptr end() const
    {
      return m_endPointer;
    }
    // TODO create a new faststring object in substr functions
    void substr(const size_t p_from, const base_ptr& p_to)
    {
      const base_ptr l_newStart = begin() + p_from;
      substr(l_newStart, p_to);
    }
    void substr(const size_t p_from, const size_t p_to = npos)
    {
      const base_ptr l_newStart = begin() + p_from;
      substr(l_newStart, p_to);
    }
    void substr(const base_ptr& p_from, const size_t p_to)
    {
      const base_ptr l_newEnd = (p_to != npos) ? begin() + p_to : end();
      substr(p_from, l_newEnd);
    }
    void substr(const base_ptr& p_from, const base_ptr& p_to)
    {
      dcassert(!isValidPointer(p_from));
#ifdef _SAVE_FASTSTRING
      if (isValidPointer(p_from))
      {
#endif // _SAVE_FASTSTRING
        m_startPointer = p_from;
        m_capacity = end() - begin();
#ifdef _SAVE_FASTSTRING
      }
#endif // _SAVE_FASTSTRING
      
      dcassert(!isValidPointer(p_to));
#ifdef _SAVE_FASTSTRING
      if (isValidPointer(p_to))
#endif // _SAVE_FASTSTRING
        m_endPointer = p_to;
        
      updateSize();
    }
    bool find(const base_fast_string& p_forFindStr, base_ptr& p_fromPointerResult) const
    {
      return find(p_forFindStr.begin(), p_forFindStr.size(), p_fromPointerResult);
    }
    bool find(const base_type* p_forFindPointer, base_ptr& p_fromPointerResult) const
    {
      return find(Pointer(p_forFindPointer), strlen(p_forFindPointer), p_fromPointerResult);
    }
    bool find(const Pointer& p_forFindPointer, size_t p_forFindSize, base_ptr& p_fromPointerResult) const
    {
      dcassert(!isValidPointer(p_fromPointerResult));
#ifdef _SAVE_FASTSTRING
      if (isValidPointer(p_fromPointerResult))
      {
#endif // _SAVE_FASTSTRING
        for (const Pointer l_maxPointerResult = end() - p_forFindSize + 1; p_fromPointerResult != l_maxPointerResult; p_fromPointerResult++)
          if (!memcmp(p_forFindPointer, p_fromPointerResult, p_forFindSize))
            return true;
            
#ifdef _SAVE_FASTSTRING
      }
#endif // _SAVE_FASTSTRING
      return false;
    }
    bool find(const base_type p_forFindChar, base_ptr& p_fromPointerResult) const
    {
      dcassert(!isValidPointer(p_fromPointerResult));
#ifdef _SAVE_FASTSTRING
      if (isValidPointer(p_fromPointerResult))
      {
#endif // _SAVE_FASTSTRING
        for (; p_fromPointerResult != end(); p_fromPointerResult++)
          if (*p_fromPointerResult == p_forFindChar)
            return true;
            
#ifdef _SAVE_FASTSTRING
      }
#endif // _SAVE_FASTSTRING
      return false;
    }
    bool rfind(const base_fast_string& p_forFindStr, base_ptr& p_fromPointerResult) const
    {
      return rfind(p_forFindStr.begin(), p_forFindStr.size(), p_fromPointerResult);
    }
    bool rfind(const base_type* p_forFindPointer, base_ptr& p_fromPointerResult) const
    {
      return rfind(Pointer(p_forFindPointer), strlen(p_forFindPointer), p_fromPointerResult);
    }
    bool rfind(const Pointer& p_forFindPointer, size_t p_forFindSize, base_ptr& p_fromPointerResult) const
    {
      dcassert(!isValidPointer(p_fromPointerResult));
#ifdef _SAVE_FASTSTRING
      if (isValidPointer(p_fromPointerResult))
      {
#endif // _SAVE_FASTSTRING
        const Pointer l_maxPointerResult = end() - p_forFindSize + 1;
        dcassert(p_fromPointerResult > l_maxPointerResult);
#ifdef _SAVE_FASTSTRING
        if (p_fromPointerResult > l_maxPointerResult)
          p_fromPointerResult = l_maxPointerResult;
#endif // _SAVE_FASTSTRING
        for (; p_fromPointerResult != begin(); p_fromPointerResult--)
          if (!memcmp(p_forFindPointer, p_fromPointerResult, p_forFindSize))
            return true;
            
#ifdef _SAVE_FASTSTRING
      }
#endif // _SAVE_FASTSTRING
      return false;
    }
    bool rfind(const base_type p_forFindChar, size_t p_forFindSize, base_ptr& p_fromPointerResult) const
    {
      dcassert(!isValidPointer(p_fromPointerResult));
#ifdef _SAVE_FASTSTRING
      if (isValidPointer(p_fromPointerResult))
      {
#endif // _SAVE_FASTSTRING
        dcassert(p_fromPointerResult > end());
#ifdef _SAVE_FASTSTRING
        if (p_fromPointerResult > end())
          p_fromPointerResult = end();
#endif // _SAVE_FASTSTRING
        for (; p_fromPointerResult != begin(); p_fromPointerResult--)
          if (*p_fromPointerResult == p_forFindChar)
            return true;
            
#ifdef _SAVE_FASTSTRING
      }
#endif // _SAVE_FASTSTRING
      return false;
    }
    int stoi(size_t *idx = 0, int base = 10) const
    {
      return strtol((base_type const *)begin(), (base_type**)&idx, base);
    }
    long stol(size_t *idx = 0, int base = 10) const
    {
      return strtol((base_type const *)begin(), (base_type**)&idx, base);
    }
    unsigned long stoul(size_t *idx = 0, int base = 10) const
    {
      return strtoul((base_type const *)begin(), (base_type**)&idx, base);
    }
    /*   TODO
    ?long long          stoll( const std::string& str, size_t *idx = 0, int base = 10);?
    (4) (C++11 feature)
    ?unsigned long long stoull( const std::string& str, size_t *idx = 0, int base = 10)?
    (5) (C++11 feature)
      */
    double stod(size_t *idx = 0/* TODO , int base = 10*/) const
    {
      return strtod((base_type const *)begin(), (base_type**)&idx);
    }
    float stof(size_t *idx = 0/*, int base = 10*/) const
    {
      return strtod((base_type const *)begin(), (base_type**)&idx);
    }
    /*
    ?float       stof( const std::string& str, size_t *idx = 0, int base = 10);?
    (1) (C++11 feature)
    ?double      stod( const std::string& str, size_t *idx = 0, int base = 10);?
    (2) (C++11 feature)
    ?long double stold( const std::string& str, size_t *idx = 0, int base = 10);?
    (3) (C++11 feature)
    */
};
//==============================================================================
/*
template<typename base_ptr, typename base_type>
class base_fast_string_mem : public base_fast_string<base_ptr>
{
  base_fast_string_mem() : data() {}
private:
    base_type data[];
};
*/
//==============================================================================

#endif // BASE_FAST_STRING_H